#include"ThreadCache.h"


void* ThreadCache::Allocate(size_t size)
{
	// 大于256KB直接向堆区获取
	if (size > MAX_BYTES)
	{
		int k = (size - 1) >> PAGE_SHIFT + 1; // 向上对齐
		span* ret=PageCache::GetInstence()->NewSpan(k);
		return (void*)(ret->_pageId<< PAGE_SHIFT);
	}


	int alignSize = SizeClass::RoundUp(size);  //对齐后的内存大小
	int index = SizeClass::Index(size);		   //内存映射下标

	
	if (!_freeLists[index].Empty())
	{
		//对应桶不为空
		return _freeLists[index].Pop();
	}

	// 当前线程缓存没有内存，向中心缓存获取
	return FetchFromCentralCache(index, alignSize);// 此时传递的是对齐后的大小
}


void ThreadCache::Deallocate(void* ptr, size_t size)
{
	assert(ptr);

	// 释放256k之上内存
	if (size > MAX_BYTES)
	{
		int id = (PAGE_ID)ptr >> PAGE_SHIFT;
		span* span1 = PageCache::GetInstence()->MapObjectToSpan(ptr);

		PageCache::GetInstence()->_pageMtx.lock();
		PageCache::GetInstence()->ReleaseSpanToPageCache(span1);
		PageCache::GetInstence()->_pageMtx.unlock();
		return;
	}
	

	// 找到对应桶加入进去
	int index = SizeClass::Index(size);
	_freeLists[index].Push(ptr);

	//如果自由链表中的个数大于一次批量则返回
	if (_freeLists[index].Size() >= _freeLists[index].MaxSize())
	{
		void* start;
		void* end;
		int n = _freeLists[index].MaxSize();// 一次拿取一批次，这个数是慢增长的
		int index = SizeClass::Index(size);
		_freeLists[index].PopRange(start, end, n);

		// 将内存交给CentralCache释放
		CentralCache::GetInstence()->ReleaseListToSpans(start, size);
	}
}




// 从中心缓存获取内存                    alignSize 对齐后的大小，与原size的index一样
void* ThreadCache::FetchFromCentralCache(size_t index, size_t size)
{
	
	// 慢开始,逐步走到上限值
	int batchNum = min(SizeClass::NumMoveSize(size), _freeLists[index].MaxSize());
	if (batchNum == _freeLists[index].MaxSize())
	{
		_freeLists[index].MaxSize() += 1;
	}

	void* start;
	void* end;
	size_t realNum=CentralCache::GetInstence()->FetchRangeObj(start, end, batchNum, size);
	
	if (realNum != 1)
	{
		//返回头一块内存给用户，其余插入对应hash链表中
		_freeLists[index].PushRange(Next(start), end, realNum-1);
	}


	return start;
}